package com.lry.pda.bottom.operation;



import com.lry.pda.topdown.SymbolDefine;

import java.util.*;

/**
 * 状态机节点
 */
public class State {
    private boolean printInfo;
    private boolean transitionDone;
    //节点编号
    private int stateNum;
    //节点管理器
    private StateManager stateManager = StateManager.getSelf();

    //节点对应的所有表达式
    private List<Production> productionList;
    private List<Production> mergedProductionList = new ArrayList<>();

    //当前节点出去的转移表
    private Map<Integer, State> transition = new HashMap<>();
    //当前节点的闭包集合
    private List<Production> closureList = new ArrayList<>();
    //表达式管理器
    private ProductionManager productionManager = ProductionManager.getSelf();
    //当前节点的分区
    private Map<Integer,List<Production>> partition = new HashMap<>();


    public State(List<Production> productionList){
        this.stateNum = StateManager.stateNum;
        this.productionList = productionList;
        this.closureList.addAll(productionList);
    }

    public void print(){
        System.out.println("节点信息如下：");
        for (Production production : productionList) {
            production.print();
        }
        System.out.println();
    }

    public void stateMerge(State state){
        //?
        if(!this.productionList.contains(state.productionList)){
            for (Production production : state.productionList) {
                //我自己没有的，他有，就把那个节点的production加入到merge
                if(!this.productionList.contains(production)&&!this.mergedProductionList.contains(production)){
                    this.mergedProductionList.add(production);
                }
            }
        }
    }

    public void buildTransition() {
        if(transitionDone){
            return;
        }
        transitionDone = true;

        makeClosure();//闭包
        partition();//分区
        makeTransition();//计算跳转关系
    }

    public int getStateNum() {
        return stateNum;
    }

    private void makeClosure() {
        Stack<Production> stack = new Stack<>();
        for (Production production : productionList) {
            stack.push(production);
        }

        while(!stack.isEmpty()){
            Production production = stack.pop();
            int symbol = production.getDotSymbol();
            //终结符不计算闭包
            if(SymbolDefine.isSymbolTerminals(symbol)){
                continue;
            }
            //获取闭包
            List<Production> closures = productionManager.getProduction(symbol);

            //计算下一个表达式的lookAhead
            Set<Integer> lookAhead = production.computeFirstSetOfBetaAndC();

            //将当前节点闭包加入闭包集合，并且放入栈中，继续步进处理，直到把当前节点所有闭包都找到
            for (Production closure : closures) {
                Production newProduction = closure.cloneSelf();
                newProduction.setLookAheadSet(lookAhead);

                if(!closureList.contains(newProduction)){
                    closureList.add(newProduction);
                    stack.push(newProduction);
                    removeRedundantProduction(newProduction);
                }
            }
        }
    }

    private void removeRedundantProduction(Production newProduct) {
        Iterator<Production> iterator = closureList.iterator();
        while(iterator.hasNext()){
            Production next = iterator.next();
            if(newProduct.coverUp(next)){
                iterator.remove();
                System.out.print("remove redundant production: ");
                next.print();
            }
        }
    }

    /**
     * 节点0, s-> .e ： 计算闭包，即点号右边e，获取左边是e的表达式 e -> .e + t，e -> .t，在对e -> .t，获取左边是t（点号右边是t）的表达式，得到0号节点所有闭包如下
     *  *
     *  *   s -> .e
     *  *   e -> .e + t
     *  *   e -> .t
     *  *   t -> .t * f
     *  *   t -> .f
     *  *   f -> .( e )
     *  *   f -> .NUM
     *  *
     *  * 分区：把上述闭包中点号右边符号相同归为一个分区
     *  *  分区1
     *  *   s -> .e        ----点号右移一位------> 节点1: s -> e. , e -> e. + t
     *  *   e -> .e + t
     *  *
     *  *  分区2
     *  *   e -> .t        ----点号右移一位------> 节点2: e -> t. , t -> t. * f
     *  *   t -> .t * f
     *  *
     *  *   分区3
     *  *   t -> .f       ----点号右移一位------> 节点3: t -> f.
     *  *
     *  *   分区4
     *  *   f -> .( e )   ----点号右移一位------> 节点4: f -> (. e )
     *  *
     *  *   分区5
     *  *   f -> .NUM     ----点号右移一位------> 节点5:  f -> NUM.
     */
    private void partition() {
        for (Production production : closureList) {
            int dotSymbol = production.getDotSymbol();
            if(dotSymbol==SymbolDefine.UNKNOWN_SYMBOL){
                continue;
            }
            partition.compute(dotSymbol,(k,v)->{
                if(null==v){
                    v = new ArrayList<>();
                }
                if(!v.contains(production)){
                    v.add(production);
                }
                return v;
            });
        }
    }

    /**
     *  计算节点0到节点1~5的跳转关系：
     *  *   节点0-----e------->节点1：(意思是当输入是e时，节点0跳转到节点1，e为节点1点号左边的符号)
     *  *   节点0-----t------->节点2
     *  *   节点0-----f------->节点3
     *  *   节点0-----(------->节点4
     *  *   节点0-----NUM------->节点5
     */
    private void makeTransition() {
        //遍历当前节点所有分区
        for (Integer symbol : partition.keySet()) {
            //构建下一个节点
            State nextState = buildNextState(symbol);
            transition.put(symbol,nextState);
            stateManager.addTransition(this,symbol,nextState);
        }

        extendFollowingTransition();
    }


    private State buildNextState(Integer symbol) {
        List<Production> productions = partition.get(symbol);
        //所有表达式点号右移一位生成新的表达式，再生成新节点
        List<Production> newStateProductions = new ArrayList<>();

        for (Production production : productions) {
            newStateProductions.add(production.dotForward());
        }

        return stateManager.buildStateByProduction(newStateProductions);
    }


    //继续去构建
    private void extendFollowingTransition() {
        for (State state : transition.values()) {
            if(state.transitionDone){
                continue;
            }
            state.buildTransition();
        }
    }

    /**
     * 节点的所有表达式必须相同
     * @param obj
     * @return
     */
    @Override
    public boolean equals(Object obj){
        State state = (State) obj;
        //需要比较表达式和lookAhead
        return checkProductionEqual(state,false);
    }

    public boolean checkProductionEqual(State state, boolean partial) {

        if (state.productionList.size() != this.productionList.size()) {
            return false;
        }

        int equalCount = 0;

        for (int i = 0; i < state.productionList.size(); i++) {
            for (int j = 0; j < this.productionList.size(); j++) {
                if (partial == false) {
                    if (state.productionList.get(i).equals(this.productionList.get(j)) == true) {
                        equalCount++;
                        break;
                    }
                }
                else {
                    if (state.productionList.get(i).productionEquals(this.productionList.get(j)) == true) {
                        equalCount++;
                        break;
                    }
                }
            }
        }

        return equalCount == state.productionList.size();
    }


    public Map<Integer,Integer> makeReduce(){
        Map<Integer, Integer> map = new HashMap<Integer, Integer>();
        reduce(map, this.productionList);
        reduce(map, this.mergedProductionList);
        return map;
    }

    private void reduce(Map<Integer, Integer> map, List<Production> productionList) {
        for (Production production : productionList) {
            if(production.canReduce()){
                Set<Integer> lookAhead = production.getLookAhead();
                for (Integer symbol : lookAhead) {
                    //lookahead,表达式编号，代表当遇到lookahead使用编号为number的表达式reduce
                    map.put(symbol,production.getNumber());
                }
            }
        }
    }


}
